


#|______________________________________________________________________________
 |
 | views001.lsp
 |
 | Contains the following constructor functions for the new ViSta Plots System:
 |
 | RELATATIONAL VIEW - SpreadPlot for matrix data
 |  1) Double center if distances (zero diagonal, range=0 to inf)
 |  2) Obtain Eigen Solution data=evecs*evals*evecsT
 |  3) Calculate scores=evecs*sqrt(evals)
 |  4) Do multivariate spreadplot of scores
 |
 | BIVARIATE VIEW (not working)
 | 
 |________________________________________________________________
 |#


  (defun missing-view () (visualize-missing-data))
  (defun Numeric-view () (visualize-data :dialog nil :multivariate t))
  (defun Category-view  () (visualize-data :dialog nil :category t))
  (defun Frequency-view      () (visualize-data :dialog nil :frequency t))

  (defun Classified-view  () (visualize-data :dialog nil :classification t))
  (defun CrossTab-view  () (visualize-data :dialog nil :crosstabs t))

  (defun pairwise-view            () (bivariate-spreadplot))
  (defun scatterplot-view    () (scatter-spreadplot))
  (defun mosaic-view () (mosaic-spreadplot))

  (defun hhD-View () (visualize-data :dialog nil :guided-tour t))
  (defun make-a-new-view ()
    (load (strcat *default-path* "source\\sketch01")))

(defun relational-view ()
  (cond
    ((equal (send $ :datatype) "matrix")
     (let* ((data (send $ :get-active-data-matrices))
            (nmat (send $ :nmat))
            (labels (send $ :active-variables '(numeric)))
            (data (sqrt (/ (apply #'+ (^ data 2)) nmat)))
            (type (four-button-dialog "These Relational Data are:" :first-button "Distances" :second-button "Correlations" :third-button "Covariances" :fourth-button "Cancel"))
            ;(mindata (min (combine data)))
            ;(maxdata (max (combine data)))
            (X (case type
                 (0 (mds-decomp data))
                 (1 (psd-decomp data))
                 (2 (psd-decomp data))
                 (t (top-level nil))))
            ;(X (mds-decomp data))
            (r (array-dimension X 1))
            (variables (mapcar #'(lambda (i) (format nil "Dim~a" i)) (iseq r)))
            (dob (data (send $ :title)
                       :data (combine X)
                       :variables variables
                       :labels labels
                       :iconify nil))
            )
       (send dob :visualize-data :multivariate t)
       ))
    (t (fatal-message "Data must be matrix data."))))


(defun mds-decomp (O &optional R)
"Args: O R
Computes Torgerson's Classical MDS of observed data in O, a symmetric (NxN) matrix of dissimilarities. Returns X, an (NxR) matrix of R-dimensional coordinates of points in Euclidean space, where R is the minimum of the specified value of R and the Rank of O. For the specific value of R, routine optimizes fit of XX' to B, where B is double-centered (^O 2)."
  (let* ((osq (^ o 2))
         (n (first (array-dimensions osq)))
         (means (mapcar #'mean (row-list osq)))
         (ones (repeat 1 n))
         (col-means (outer-product ones means))
         (B (* -.5 (+ (- osq col-means (transpose col-means)) (mean means))))
         (svd (sv-decomp B))
         (singvecs (first svd))
         (sqrt-singvals (sqrt (second svd)))
         (rank (length (which (> sqrt-singvals (mean sqrt-singvals)))))
         (R (if R (min rank R) rank))
         (L (diagonal (select sqrt-singvals (iseq r))))
         (U (select (first svd) (iseq n) (iseq r))))
    (matmult U L)))


(defun double-center (O)
  (let* ((osq (^ o 2))
         (n (first (array-dimensions osq)))
         (means (mapcar #'mean (row-list osq)))
         (ones (repeat 1 n))
         (col-means (outer-product ones means)))
    (* -.5 (+ (- osq col-means (transpose col-means)) (mean means)))))

(defun psd-decomp (O &optional R)
  (let* ((svd (sv-decomp O))
         (n (first (array-dimensions o)))
         (singvecs (first svd))
         (sqrt-singvals (sqrt (second svd)))
         (rank (length (which (> sqrt-singvals (mean sqrt-singvals)))))
         (R (if R (min rank R) rank))
         (L (diagonal (select sqrt-singvals (iseq r))))
         (U (select (first svd) (iseq n) (iseq r))))
    (matmult U L)))


(defun view 
  (sizes plot-symbol-list 
         &key supplemental-plot statistical-object (menu-title "SpreadPlot") show 
         (local-links t) (location nil)
         (size (floor (* .9 (effective-screen-size))))
         rel-widths rel-heights span-right span-down
         (data-object $) (container nil))
  (if container 
      (enable-container container)
      (setf container (send data-object :create-spreadplot-container 0)))
  (let* ((view container)
         (result)
         (plot-object-list)
         (splot))
    (dolist (plot-symbol plot-symbol-list)
            (setf result 
                  (case plot-symbol
                    (histogram-plot    (histogram-plot    $ :in view))
                    (distribution-plot (distribution-plot $ :in view))
                    (cumulative-plot   (cumulative-plot   $ :in view))
                    (comparison-plot   (comparison-plot   $ :in view))
                    (dot-plot          (dot-plot          $ :in view))
                    (scatter-plot      (scatter-plot      $ :in view))
                    (scatter-matrix    (scatter-matrix    $ :in view))
                    (spinning-plot     (spinning-plot     $ :in view))
                    (orbiting-plot     (orbiting-plot     $ :in view))
                    (line-plot         (line-plot         $ :in view))
                    (box-plot          (box-plot          $ :in view))
                    (diamond-plot      (diamond-plot      $ :in view))
                    (catbox-plot       (catbox-plot       $ :in view))
                    (paracoord-plot    (paracoord-plot    $ :in view))
                    (mosaic-plot       (mosaic-plot       $ :in view))
                    (bar-graph         (bar-graph         $ :in view))
                    (labels-list       (labels-list       $ :in view))
                    (variables-list    (variables-list    $ :in view))
                    (categories-list   (categories-list   $ :in view))))
            (setf plot-object-list (append plot-object-list (list result))))
    (setf splot (spreadplot (matrix sizes plot-object-list)
                          :container view :style 0))
    (send splot :show-spreadplot)
    (disable-container)
    (defmeth container :close () (send self :hide-window))
    splot
    ))
#|________________________________________________________________
 |
 | BIVARIATE-VIEW - matrix of bivariate plots for all pairs of variables
 |
 |   ALL BIVARIATE VIEWS - alias for menus
 |   BIVAR-SPLOT - alias for typing
 |________________________________________________________________
 |#

(defun bivariate-view (&key (data $) (container nil) (content-only nil))
"Args: &key (data-object $)  (container nil)
Used by the menuing system to present scatterplots."
  (if container 
      (enable-container container)
      (send data :create-spreadplot-container 1))
  (send *spreadplot-container* :pop-out t)
  (send *spreadplot-container* :title "Bivariate SpreadPlot")
  (let* ((data-object data)
         (quant-vars    (send data-object :active-variables '(numeric )))
         (qual-vars     (send data-object :active-variables '(category ordinal)))
         (n-quant-vars  (length quant-vars))
         (n-qual-vars   (length qual-vars))
         (n-vars (+ n-quant-vars n-qual-vars))
         (pw (setf *please-wait* (please-wait "Bivariate Plots: Making Quant Vars SubMatrix 00")))
         (quant-plotmatrix (cond 
                             ((= n-quant-vars 0) nil)
                             (t
                              (quant-plotobject-matrix 
                               data-object *spreadplot-container*))))
         (quant-plotmatrix (if (and (= n-qual-vars 0) (= n-quant-vars 2) )
                               (matrix '(2 1) 
                                       (list (aref quant-plotmatrix 1 0)
                                             (aref quant-plotmatrix 1 1)))
                               quant-plotmatrix))
         (pw (setf *please-wait* (please-wait "Bivariate Plots: Making Mixed Vars SubMatrix 01")))
         (mixed-plotmatrix01  (if (and (> n-quant-vars 0)(> n-qual-vars 0))
                                (transpose (mixed-plotobject-matrix 
                                            data-object *spreadplot-container*))))
         (pw (setf *please-wait* (please-wait "Bivariate Plots: Making Mixed Vars SubMatrix 10")))
         (mixed-plotmatrix10  (if (and (> n-quant-vars 0)(> n-qual-vars 0))
                                (mixed-plotobject-matrix 
                                 data-object *spreadplot-container*)))
         (pw (setf *please-wait* (please-wait "Bivariate Plots: Making Categ Vars SubMatrix 11")))
         (categ-plotmatrix (if (> n-qual-vars 2)
                               (categ-plotobject-matrix
                                data-object *spreadplot-container*)))
         (plotmat)
         (splot))
    (setf *please-wait* (please-wait "Bivariate Plots: Making SuperMatrix"))
    (cond 
      ((< (+ n-qual-vars n-quant-vars) 2)
       (vista-message (format nil "~%At least two variables must be selected.")))
      ((= 0 n-qual-vars)  (scatterplots) (boxplots))
      ((= 0 n-quant-vars) (mosaicplots))
      ((and (= 1 n-qual-vars) (= 1 n-quant-vars)) (boxplots))
      (t   
       (setf plotmat (cond 
                       ((and quant-plotmatrix mixed-plotmatrix01)
                        (if categ-plotmatrix
                            (bind-rows
                             (bind-columns quant-plotmatrix   mixed-plotmatrix01)
                             (bind-columns mixed-plotmatrix10 categ-plotmatrix))
                            (bind-columns quant-plotmatrix mixed-plotmatrix01)))
                       (quant-plotmatrix quant-plotmatrix)
                       (mixed-plotmatrix01  mixed-plotmatrix01)
                       (t (error "; impossible condition"))))
       (if (> (first (size plotmat)) (second (size plotmat))) 
           (setf plotmat (transpose plotmat)))
       (setf *please-wait* (please-wait "Bivariate Plots: Making SpreadPlot"))
       (setf splot (spreadplot plotmat :style 1))
       (when (and quant-plotmatrix (or (> (array-dimension plotmat 0) 2)
                                     (> (array-dimension plotmat 1) 3)))
             (setf *please-wait* (please-wait "Bivariate Plots: Undecorating 00"))
             (quant-change-features 
              (size quant-plotmatrix) quant-plotmatrix quant-vars)
             (setf *please-wait* (please-wait "Bivariate Plots: Undecorating 01"))
             (mixed-change-features mixed-plotmatrix01  qual-vars quant-vars)
             (setf *please-wait* (please-wait "Bivariate Plots: Undecorating 10"))
             (mixed-change-features mixed-plotmatrix10   quant-vars qual-vars))
       (setf *please-wait* (please-wait "Bivariate Plots: Showing"))
       (send splot :show-spreadplot )
       (send *spreadplot-container* :pop-out t)
       splot))
    ))

#|________________________________________________________________
 |
 | SCATTER-SPREADPLOT - all pairs of scatterplots
 |
 |   ALL NUMERIC BIVARIATE VIEWS - alias for menus
 |   SCATTER-SPLOT - alias for typing
 |________________________________________________________________
 |#

(defun all-numeric-bivariate-views (&key (data $) (container nil) (content-only nil))
"Keyword Args: (data-object $) (content-only t) (container nil)
Presents a spreadplot of all pairs of scatterplots with normal-probability plots on the diagonal."
  (scatter-spreadplot :data data :container container :content-only content-only))

(defun scatter-splot () (&key (data $) (container nil) (content-only nil))
"Keyword Args: (data-object $) (content-only t) (container nil)
Presents a spreadplot of all pairs of scatterplots with normal-probability plots on the diagonal."
  (scatter-spreadplot :data data :container container :content-only content-only))

(defun scatter-spreadplot (&optional (data $) (container nil) (content-only nil))
"Keyword Args: (data-object $) (content-only t) (container nil)
Presents a spreadplot of all pairs of scatterplots with normal-probability plots on the diagonal."
  (if container (enable-container container)
      (setf container (send data :create-spreadplot-container 1)))
  (let* ((data-object data)
         (num-data 
          (column-list 
           (send data-object :active-data-matrix '(numeric))))
         (num-num-vars (length num-data))
         (plot)
         )
    (cond 
      ((< num-num-vars 2)
       (vista-message (format nil "~%ScatterPlots can only be constucted when the active variables include two or more \"numeric\" variables.")))
      (t
       (setf plot (quant-spreadplot data-object container))
       (send *spreadplot-container* :pop-out t)
       ))
    plot))


(defun quant-spreadplot (&optional (data-object $) (container nil))
"Args: (&optional (data-object $) (content-only t) (container nil)
Makes a spreadplot of scatterplots and normal-probability plots formed by crossing all numeric variables with themselves"
  (if container 
      (enable-container container)
      (send data-object :create-spreadplot-container 1))
  (let* ((quant-plotmatrix (quant-plotobject-matrix data-object container)) 
         (numeric-variables (send data-object :active-variables '(numeric)))
         (splot (spreadplot quant-plotmatrix :container container :style 1))
         (ss (size quant-plotmatrix))
         (newmenu (send menu-proto :new "PopUp"))
         )
    (quant-change-features ss quant-plotmatrix numeric-variables)
    (send splot :show-spreadplot)
    (disable-container)
    splot))
 

(defun quant-plotobject-matrix 
  (&optional (data-object $) (container nil))
"ARGS: (&optional (data-object $) (content-only nil) (container nil))
Returns a matrix with scatterplots off-diagonal and normal-probability plots on diagonal where there is one row and column for each quantitative variable."
  (let* ((actcon *active-container*)
         (*speadplot-container*
          (if container (enable-container container)
              (send data-object :create-spreadplot-container 0)))
         (numeric-variables (send data-object :active-variables '(numeric)))
         (nn (length numeric-variables))
         (numeric-data 
          (column-list (send data-object :active-data-matrix '(numeric))))
         (scat)(varlab)
         (quant-plotmatrix
          (matrix (list nn nn) 
                  (combine 
                   (mapcar 
                    #'(lambda (x-var j)
                        (setf x-var (coerce x-var  'list))
                        
                        (mapcar 
                         #'(lambda (y-var i)
                             (cond
                               ((= i j)
                                (normal-probability-plot 
                                       x-var
                                       :in container
                                       :legend1 (select numeric-variables i)
                                       :line-plot t
                                       :reg-line t)
                                      )
                               (t
                                (setf y-var (coerce y-var 'list))
                                (setf varlab (select numeric-variables (list i j)))
                                (setf scat
                                      (scatterplot (list x-var y-var)
                                                   :in container
                                                   ; :content-only content-only
                                                   :variable-labels varlab
                                                   ))
                                )))
                         numeric-data (iseq nn) ))
                    numeric-data (iseq nn)))))
         )
    (disable-container)
    (enable-container actcon)
    quant-plotmatrix))
    

     
(defun quant-change-features (ss quant-plotmatrix numeric-variables)
  (let* ((scat)
         (menu)
         (items)
         (newmenu)
         )
    (dotimes 
     (i (first ss))
             
     (dotimes 
      (j (second ss))
      (setf scat (aref quant-plotmatrix i j))
      (send scat :x-axis nil)
      (send scat :y-axis nil)
      (send scat :legend1 " ")
      (send scat :legend2 " ")
      (send (send scat :menu) :remove)
      (defmeth scat :redraw-overlays ())
      (send scat :margin 0 0 0 0)
      (send scat :use-color t)
              (send scat :point-color (iseq (send scat :num-points)) 'blue)
              (send scat :mouse-mode 'brushing)
              (send scat :linked t)
      ))
    ))

#|______________________________________________________________________
 |
 | MOSAIC-SPREADPLOT - all pairs of bivariate mosaic plots
 |
 | ALL CATEGORICAL BIVARIATE VIEWS - alias for menu system
 | MOSAIC-SPLOT - alias for typing
 |______________________________________________________________________
 |#


(defun all-categorical-bivariate-views (&key (data $) (container nil) (content-only nil))
"Keyword Args: (data-object $) (content-only t) (container nil)
Presents a spreadplot of all pairs of bivariate mosaic plots with univariate mosaic plots on the diagonal."
  (mosaic-spreadplot :data data :container container :content-only content-only))

(defun mosaic-splot (&key (data $) (container nil) (content-only nil))
"Keyword Args: (data-object $) (content-only t) (container nil)
Presents a spreadplot of all pairs of bivariate mosaic plots with univariate mosaic plots on the diagonal."
  (mosaic-spreadplot :data data :container container :content-only content-only))

(defun mosaic-spreadplot (&key (data-object $) (container nil) (content-only nil))
"Args: (&optional (data-object $) (content-only t) (container nil) (content-only nil)
Presents a spreadplot of all pairs of bivariate mosaic plots with univariate mosaic plots on the diagonal."
  (if container (enable-container container)
      (send data-object :create-spreadplot-container 1))
  (let* ((categ-plotmatrix (categ-plotobject-matrix data-object container)) 
         (categ-variables (send data-object :active-variables '(category)))
         (splot (spreadplot categ-plotmatrix :container container :style 1))
         (ss (size categ-plotmatrix))
        ; (newmenu (send menu-proto :new "PopUp"))
         )
    (cat-change-features categ-plotmatrix)
    (send splot :show-spreadplot)
    ;(disable-container)
    splot))


(defun categ-plotobject-matrix 
  (&optional (data-object $) (container nil))
"ARGS: (&optional (data-object $) (content-only nil) (container nil))
Returns a matrix of mosaicplots where there is one row and column for each categorical variable."
  (let* ((actcon *active-container*)
         (*speadplot-container*
          (if container (enable-container container)
              (send data-object :create-spreadplot-container 0)))
         (category-variables (send data-object :active-variables '(category)))
         (nn (length category-variables))
         (category-data 
          (column-list (send data-object :active-data-matrix '(category))))
         (scat)(varlab)
         (categ-plotmatrix
          (matrix (list nn nn) 
                  (combine 
                   (mapcar 
                    #'(lambda (x-var j)
                        (setf x-var (coerce x-var  'list))
                        (mapcar 
                         #'(lambda (y-var i)
                             (setf y-var (coerce y-var 'list))
                             (setf plot 
                                   (if (= i j)
                                       (mosaic-plot 
                                        (list x-var) 
                                        :way-labels (select category-variables (list i))
                                       ; :content-only t
                                        :in *spreadplot-container*)
                                       (mosaic-plot 
                                        (list x-var y-var) 
                                        :way-labels (select category-variables (list i j))
                                       ; :content-only t
                                        :in *spreadplot-container*))))
                         category-data (iseq nn)))
                    category-data (iseq nn))))))
    ;(disable-container)
    ;(enable-container actcon)
    categ-plotmatrix))



(defun cat-change-features (cat-plotmatrix)
  (let* ((g))
    (dotimes (i (array-dimension cat-plotmatrix 0))
             (dotimes (j (array-dimension cat-plotmatrix 0))
                      (setf g (select cat-plotmatrix i j))
                      (send g :x-axis nil)
                      (send g :y-axis nil)
                      (send g :legend1 " ")
                      (send g :legend2 " ")
                      (send g :delete-overlay (first (send g :overlays)))
                     ; (send g :margin 28 0 5 12)
                      (send g :margin 40 -6 5 40)
                      ))))





#|__________ BOXPLOTS SPREADPLOT CONSTRUCTOR FUNCTIONS ______________|#


(defun boxplots (&rest args) (apply #'grouped-box-plots args))

(defun box-plots (&rest args) (apply #'grouped-box-plots args))

(defun grouped-boxplots (&optional (data-object $) (container nil) )
  (grouped-box-plots :data-object data-object :container containera))

(defun grouped-box-plots (&optional (data-object $) (container nil) )
"Args: None
Used by the menuing system to present boxplots. Determines which kind of boxplot is appropriate"
   (if container (enable-container container)
      (send data-object :create-spreadplot-container 0))
  (let* ((num-data 
          (column-list 
           (send data-object :active-data-matrix '(numeric))))
         (num-num-vars (length num-data))
         (num-qual-vars (length (send data-object :active-variables '(category ordinal))))
         (num-total-vars (+ num-num-vars num-qual-vars))
         (plot)
         )
    (cond 
      ((= num-num-vars 0)
       (vista-message (format nil "~%BoxPlots can only be constucted when the active variables include one or more whose variable type is \"numeric\".")))
      ((= num-qual-vars 0)
       (setf newcon (container :in nil :show nil))
       (setf plot (boxplot num-data 
                             :equate t
                             :connect-points t
                             :title (if (> num-num-vars 1) 
                                        "Side-by-Side Box Plots" 
                                        "Box Plot")))
       (send plot :location 100 100)
       (send plot :size 400 300)
       (send plot :pop-out t))
      (t
       (setf plot (box-spreadplot data-object *spreadplot-container* ))
       (send *spreadplot-container* :pop-out t)
       ))
    plot))




(defun box-spreadplot (&optional (data-object $) (container nil))
"Args: (&optional (data-object $) )
Makes a spreadplot of boxplots formed by crossing all numeric variables with all qualitative (category and ordinal) variables"
  (let* ((mixed-plotmatrix (mixed-plotobject-matrix data-object container))
         
         (numeric-variables (send data-object :active-variables '(numeric)))
         (qualitative-variables (send data-object :active-variables '(ordinal category)))
         (ad (array-dimensions mixed-plotmatrix))
         (splot)
         )
    (mixed-change-features mixed-plotmatrix numeric-variables qualitative-variables)
    (setf  splot (spreadplot (if (< (first ad) (second ad))
                                mixed-plotmatrix
                                (transpose mixed-plotmatrix))))
    (send splot :show-spreadplot )
    (disable-container)
    ))

(defun mixed-change-features (mixed-plotmatrix numeric-variables qualitative-variables)
  (let* ((plot)
         (ad (array-dimensions mixed-plotmatrix))
         )
  (dotimes (i (first ad))
           (dotimes (j (second ad))
                      
                    (setf plot (aref mixed-plotmatrix i j))
                    (send plot :content-only t)
                    (send plot :x-axis nil)
                    (send plot :y-axis nil)
                    (send plot :legend2 " ")
                    (send plot :legendX (select qualitative-variables i))
                    (send plot :legendY (select numeric-variables j))
                    (send plot :margin 5 0 0 5)
                    (defmeth plot :redraw-overlays ())
                    (send plot :use-color t)
                    (send plot :point-color (iseq (send plot :num-points)) 'blue)
                    (send plot :mouse-mode 'brushing)
                    (send plot :linked t)
                    ))))

(defun mixed-plotobject-matrix 
  (&optional (data-object $) (container nil))
"ARGS: (&optional (data-object $) (content-only nil) (container nil))
Returns a matrix of boxplots or side-by-side boxplots where there is one row for each qualitative variable and one column for each quantitative variable."
  (let* ((actcon *active-container*)
         (*speadplot-container*
          (if container (enable-container container)
              (send data-object :create-spreadplot-container 0)))
         (numeric-variables (send data-object :active-variables '(numeric)))
         (qualitative-variables (send data-object :active-variables '(category)))
         (nn (length numeric-variables))
         (nq (length qualitative-variables))
         (numeric-data 
          (column-list (send data-object :active-data-matrix '(numeric))))
         (qualitative-data 
          (column-list (send data-object :active-data-matrix '(category))))
         (bplt)(varlab)
         (mixed-plotmatrix
          (matrix (list nq nn) 
                  (combine 
                   (mapcar 
                    #'(lambda (x-var j)
                        (setf x-var (coerce x-var  'list))
                        (mapcar 
                         #'(lambda (y-var i)
                             (setf y-var (coerce y-var 'list))
                             (setf varlab (remove-duplicates x-var :test #'equal))
                             (setf bplt
                                   (category-boxplot y-var x-var
                                                     :mean-line t :median-line t
                                            :variable-labels varlab
                                            :legendX (select qualitative-variables j)
                                            :legendY (select numeric-variables i) 
                                            :legend1  " "
                                            ))
                             
                             )
                         numeric-data (iseq nn)))
                    qualitative-data (iseq nq)))
                  )))
    (disable-container)
    (enable-container actcon)
    mixed-plotmatrix))
 




#|__________ BOX-SUPERPLOT and BOX-SPREADPLOT FUNCTION ______________|#

(defun box-superplot (&optional (data-object $) )
"Args: (&optional (data-object $) (content-only t))
Makes a spreadplot of boxplots formed by crossing all numeric variables with all qualitative (category and ordinal) variables with a side-by-side boxplot for all numerical variables at the bottom."
  (send data-object :create-spreadplot-container 0)
  (let* ((num-data 
          (column-list 
           (send data-object :active-data-matrix '(numeric))))
         (num-num-vars (length num-data))
         (num-qual-vars (length (send data-object :active-variables '(category ordinal))))
         (mixed-plotmatrix 
          (mixed-plotobject-matrix data-object content-only *spreadplot-container*))
         (ad (array-dimensions mixed-plotmatrix))
         (boxplot (boxplot num-data :equate t :connect-points t
                           :content-only content-only
                           :size (list 400 300) :location (list 100 100)
                           :title (if (> num-num-vars 1) 
                                      "Side-by-Side Box Plots" "Box Plot")))
         (splot (spreadplot (bind-rows 
                             mixed-plotmatrix
                             (matrix (list 1 num-num-vars) 
                                     (combine boxplot (repeat 'nil (1- num-num-vars)))))
                            :span-right (matrix (list (1+ num-qual-vars) num-num-vars)
                                                (combine (repeat 1 (* num-qual-vars
                                                                      num-num-vars))
                                                         num-num-vars
                                                         (repeat 0 (1- num-num-vars))))
                 ))
         )
    (send splot :show-spreadplot)
    (disable-container)
    ))

